import random
import string
import redis
from django.contrib.auth.hashers import check_password
from django.http.response import HttpResponse
from django.db.models import Q

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler

from .models import User
from captcha.image import ImageCaptcha


class GenerateImageCode(APIView):
    def get(self, request, img_id):

        # random.sample: 随机采集指定位数的字符
        salt = ''.join(random.sample(string.ascii_letters+string.digits, 4))

        # 生成一张图片
        img = ImageCaptcha()

        # 把生成的随机数字添加图片上
        image = img.generate(salt)

        # 连接redis
        redis_cli = redis.Redis(host="localhost", port=6379, password=123)

        # 存储图片验证码， 设置过期时间
        imgId = 'img_{}'.format(img_id)
        redis_cli.setex(imgId, 300, salt)

        # 返回图片
        return HttpResponse(image, content_type="image/jpg")


class CheckImageCode(APIView):
    def get(self, request):
        """ 校验图片验证码
        1. 获取前端请求是传递的图片id和用户输入的图片内容
        2. 根据有图片id的redis 中查询redis中的保存图片内容
        """
        image_id = request.query_params.get('imageCodeID')
        image_code = request.query_params.get('imageCode')
        redis_cli = redis.Redis(host="localhost", port=6379, password=123)
        result = redis_cli.get('img_{}'.format(image_id))
        if result:
            if result.decode().lower() != image_code.lower():
                return Response({'msg': '验证码输入错误'})
            else:
                return Response({'code': 200})
        else:
            return Response({"msg": '验证码已经过期'})


class CheckUsername(APIView):
    def get(self, request, name):
        """ 判断用户名是否重复"""
        rest = User.objects.filter(username=name).count()
        if rest > 0:
            return Response({'msg': '用户名已经存在', 'code': '400'})
        return Response({'code': '200'})


class CheckMobile(APIView):
    def get(self, request, mobile):
        """ 判断手机号是否重复 """
        rest = User.objects.filter(mobile=mobile).count()
        if rest > 0:
            return Response({'msg': '手机号已经存在', 'code': 400})
        return Response({'code': 200})


class UserRegister(APIView):
    def post(self, request):
        """
        注册业务逻辑
        """
        username = request.data.get('userName')
        pwd = request.data.get('pwd')
        mobile = request.data.get('mobile')
        agree = request.data.get('agree')

        if not all([username, pwd, mobile, agree]):
            return Response({'msg': "请输入完善注册用户信息", "code": 400})

        if not agree:
            return Response({"msg": "请勾选协议"})

        User.objects.create_user(username=username, password=pwd, mobile=mobile)
        return Response({'msg': "注册成功!", "code": 200})


class Login(APIView):
    """登录"""
    # 第2种多方式登录, 不用重写django的认证后端
    def post(self, request):
        user_name = request.data.get('user')
        pwd = request.data.get('pwd')

        # 对前端传来的用户名和密码进行校验
        try:
            user = User.objects.get(Q(username=user_name) | Q(mobile=user_name))
        except User.DoesNotExist as e:
            return Response({'msg': "此用户不存在,请先注册", "code": 400})

        # 2. 若存在数据库中, 前端传来的密码是否和数据库中的一样
        is_correct = check_password(pwd, user.password)

        # 返回true,说明用户名和密码匹配
        if is_correct:
            # 生成token, 把生成的token返回
            # 传入第二部分的用户信息
            payload = jwt_payload_handler(user)

            # 根据第二部分生成token
            token = jwt_encode_handler(payload)

            # 把token 写入cookie,便于退出
            resp = Response({'msg': "登录成功", "code": 200, 'user': {"userName": user.username}, "token": token})

            # 设置cookie 中
            resp.set_cookie('token', token)
            return resp
        else:
            return Response({'msg': "用户名密码错误", "code": 400})


class Logout(APIView):
    def post(self, request):
        """退出登录"""
        token = request.COOKIES.get('token')
        if token:
            del token
        return Response({'msg': "退出成功!", "code": 200})
